package ferp.android.tasks.center;

import android.content.Context;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.preference.PreferenceManager;
import android.view.View;
import android.widget.TextView;
import com.google.gson2.reflect.TypeToken;
import ferp.android.BuildConfig;
import ferp.android.activities.preferences.Preferences;
import ferp.android.ads.interstitial.InterstitialAdManager;
import ferp.android.managers.NewsManager;
import ferp.android.managers.PollManager;
import ferp.android.managers.ProfileManager;
import ferp.center.Message;
import ferp.center.client.Action;
import ferp.center.network.request.RequestConfigGet;
import ferp.center.network.response.ResponseConfigGet;
import ferp.core.ai.strategy.simple.SimpleBidding;
import ferp.core.game.Game;
import ferp.core.game.Levels;
import ferp.core.log.Log;
import ferp.core.player.Profile;

import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Date;

/**
 * User: igorgok
 * Date: 12/9/12 5:14 PM
 */
public class TaskCenterConfigGet extends AsyncTask<Void, Void, Collection<Message>>
{
  public static void requireConfigGet(SharedPreferences sp)
  {
    sp.edit().remove(TaskCenterConfigGet.CONFIG_LAST_UPDATED).commit();
  }

  public static void execute(Context context, ProfileManager pm, TextView mtv)
  {
    if (pm.getCurrentProfile() != null)
      new TaskCenterConfigGet(context, pm, mtv).execute();
  }

  public static float getBidContributionThreshold(SharedPreferences sp) {return sp.getInt(CONFIG_BID_NN_THRESHOLD, 0);}

  protected TaskCenterConfigGet(Context context, ProfileManager pm, TextView mtv)
  {
    this.context = context.getApplicationContext();
    this.device = Preferences.getDeviceID(context);
    this.pm = pm;
    this.mtv = mtv;
  }

  @Override
  protected Collection<Message> doInBackground(Void... voids)
  {
    Collection<Message> messages = null;

    try
    {
      SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
      long last = sp.getLong(CONFIG_LAST_UPDATED, 0), now = System.currentTimeMillis();

      // request NN config once a day to reduce traffic unless we're in debug mode
      if (BuildConfig.DEBUG || now - last > MS_IN_DAY)
      {
        Profile profile = pm.getCurrentProfile();
        RequestConfigGet request = new RequestConfigGet();

        // get current config ID
        request.device = device;
        request.version = pm.version();
        request.date = new Date();
        request.locale = profile.settings.locale;
        request.id = sp.getLong(CONFIG_ID, 0);
        request.profile = profile.centerId;
        request.lastBidNNID = sp.getLong(CONFIG_BID_NN_ID, 0);
        request.lastPollID = PollManager.getLastPollID(sp);
        request.debug = BuildConfig.DEBUG;

        try
        {
          // make the request
          ResponseConfigGet response = Action.execute(Action.CONFIG_GET, request, ResponseConfigGet.class);

          if (response != null)
          {
            // enable editing preferences
            SharedPreferences.Editor editor = sp.edit();

            // save last config get date
            editor.putLong(CONFIG_LAST_UPDATED, now);
            // save configuration ID only if its new
            if (response.id != request.id)
              editor.putLong(CONFIG_ID, response.id);

            // bid NN configuration
            if (response.bidding != null)
            {
              // save enabled state
              if (response.bidding.enable != sp.getBoolean(CONFIG_BID_NN_ENABLE, false))
                editor.putBoolean(CONFIG_BID_NN_ENABLE, response.bidding.enable);
              // save bid contributor score threshold
              if (response.bidding.threshold != sp.getInt(CONFIG_BID_NN_THRESHOLD, 0))
                editor.putInt(CONFIG_BID_NN_THRESHOLD, response.bidding.threshold);

              // if there is a new NN configuration store it locally
              if (response.bidding.nnj != null)
              {
                editor.putLong(CONFIG_BID_NN_ID, response.bidding.id);
                editor.putString(CONFIG_BID_NN_DATA, response.bidding.nnj);

                Log.debug(Log.TAG, "downloaded and saved bidding NN configuration of size " + response.bidding.nnj.length());
              }
            }

            // get levels information
            if (response.levels != null)
            {
              editor.putString(CONFIG_LEVELS_DATA, response.levels.data);

              Log.debug(Log.TAG, "new opponent levels configuration: " + response.levels.data);
            }

            // retrieve messages
            if (response.messages != null)
              editor.putString(CONFIG_MESSAGE_DATA, response.messages);

            // save interstitial flag
            editor.putString(CONFIG_AD, Game.gson.toJson(response.ad));
            editor.commit();

            // set poll
            PollManager.set(context.getResources(), response.poll);
          }
          else
            Log.debug(Log.TAG, "failed to receive configuration");
        }
        catch (Exception e)
        {
          Log.error(Action.TAG, e);
        }
      }

      // setup the bidding NN; if failed require reload bid NN data
      if (!SimpleBidding.init(sp.getBoolean(CONFIG_BID_NN_ENABLE, false) ? sp.getString(CONFIG_BID_NN_DATA, null) : null))
        sp.edit().remove(TaskCenterConfigGet.CONFIG_LAST_UPDATED)
                 .remove(TaskCenterConfigGet.CONFIG_BID_NN_ID)
                 .remove(TaskCenterConfigGet.CONFIG_BID_NN_DATA)
                 .commit();

      // update opponent levels information
      Levels.update(Game.gson, sp.getString(CONFIG_LEVELS_DATA, null));
      // load messages
      messages = Game.gson.fromJson(sp.getString(CONFIG_MESSAGE_DATA, null), ListOfMessages);

      // update interstitial display enabled state
      ResponseConfigGet.Ad ad = Game.gson.fromJson(sp.getString(CONFIG_AD, null), ResponseConfigGet.Ad.class);
      InterstitialAdManager.setEnabled(ad != null && ad.interstitial != null && ad.interstitial.enabled);
    }
    catch (Exception e)
    {
      Log.error(Action.TAG, e);
    }

    return messages;
  }

  @Override
  protected void onPostExecute(Collection<Message> messages)
  {
    super.onPostExecute(messages);

    // handle messages
    if (messages != null && messages.size() > 0)
      NewsManager.show(context, messages, mtv);
    else
      if (mtv != null)
        mtv.setVisibility(View.GONE);
  }

  // names for stored values
  // common config
  private static final String CONFIG_ID               = "config_id";
  private static final String CONFIG_LAST_UPDATED     = "config_last_updated";
  // bidding NN config
  private static final String CONFIG_BID_NN_ID        = "config_bid_nn_id";
  private static final String CONFIG_BID_NN_ENABLE    = "config_bid_nn_enabled";
  private static final String CONFIG_BID_NN_DATA      = "config_bid_nn_data";
  private static final String CONFIG_BID_NN_THRESHOLD = "config_bid_nn_threshold";
  // messages
  private static final String CONFIG_MESSAGE_DATA     = "config_message_data";
  // opponent levels
  private static final String CONFIG_LEVELS_DATA      = "config_levels_data";
  // interstitial ad flag
  private static final String CONFIG_AD               = "config_ad";

  // message collection type
  private static final Type ListOfMessages = new TypeToken<Collection<Message>>(){}.getType();
  // number of milliseconds in day
  private static final long MS_IN_DAY = 24 * 60 * 60 * 1000;

  private final Context context;
  private final String device;
  private final ProfileManager pm;
  private final TextView mtv;
}
